#include "files.hpp"
#include "lexer.hpp"
#include "parser.hpp"
#include "io.hpp"
#include "utils.hpp"
#include "dirent.h"
#include "sys/stat.h"

#include <fstream>
#include <cstring>

Variable bi_run(vector<Variable>& argv, Environment& env)
{
	Variable ret;
	int argc = (int)argv.size();
	if(argc!=2) {
		throw_error(ERROR_ARGUMENTCOUNT);
	}
	fstream parsetest;
	string filename = argv[1].str;
	if(isAbsolutePath(filename)) {
		if(filename.size() > 3) {
			if(filename.substr(filename.size()-3,3)!=FILEXT) {
				filename += FILEXT;
			}
		} else {
			filename += FILEXT;
		}
		parsetest.open(filename.c_str());
	} else {
		parsetest.open(findfile(env,filename).c_str());
	}
	if(!parsetest.is_open()) {
		throw_error(ERROR_FILE);
	}
	env.inscope();
	string full="";
	do{
		getline(parsetest,full);
		try{
			orate(full,env,DISABLESCOPE,parsetest);
		} catch(ErrorType e) {
			
		}
	}while(parsetest.good());
	env.outscope();
	parsetest.close();
	ret = env.getvar("__return__");
	return ret;
}

Variable bi_source(vector<Variable>& argv, Environment& env) {
	Variable ret;
	if(argv.size() != 1) {
		throw_error(ERROR_ARGUMENTCOUNT);
	}
	fstream parsetest;
	string filename = env._paths.at(0) + PATHSEPARATOR + "config.orc";
	parsetest.open(filename.c_str());
	if(!parsetest.is_open()) {
		throw_error(ERROR_FILE);
	}
	
	env.inscope();
	string full="";
	do{
		getline(parsetest,full);
		try{
			orate(full,env,DISABLESCOPE,parsetest);
		} catch(ErrorType e) {
			
		}
	}while(parsetest.good());
	env.outscope();
	parsetest.close();
	ret = env.getvar("__return__");
	return ret;
}

Variable bi_import(vector<Variable>& argv, Environment& env)
{
	Variable ret;
	int argc = (int)argv.size();
	if(argc!=2) {
		throw_error(ERROR_ARGUMENTCOUNT);
	}
	fstream parsetest;
	string filename = argv[1].str;
	if(isAbsolutePath(filename)) {
		if(filename.size() > 3) {
			if(filename.substr(filename.size()-3,3)!=FILEXT) {
				filename += FILEXT;
			}
		} else {
			filename += FILEXT;
		}
		parsetest.open(filename.c_str());
	} else {
		parsetest.open(findfile(env,filename).c_str());
	}
	if(!parsetest.is_open()) {
		throw_error(ERROR_FILE);
	}
	env.inscope();
	string full="";
	vector<Variable> cmd;
	do{
		getline(parsetest,full);
		try {
			cmd=tokenize(full,env,DISABLESCOPE,parsetest);
			if( (cmd[0].str=="import") || (cmd[0].str=="alias") || (cmd[0].str=="delete") ) {
				parse(cmd,env);
			}
		} catch(ErrorType e) {
			
		}
	}while(parsetest.good());
	env.outscope();
	parsetest.close();
	ret = env.getvar("__return__");
	return ret;
}

Variable bi_path(vector<Variable>& argv, Environment& env)
{
	Variable ret;
	int argc = (int)argv.size();
	if( (argc < 2) || (argc > 3 ) ) {
		throw_error(ERROR_ARGUMENTCOUNT);
	}
	Variable cmd = argv[1];
	if(cmd.type!=tVarname) {
		throw_error(ERROR_ARGUMENTS);
	}
	if( (argc==2) && (cmd.str == "get") ) {
		ret.type = tArray;
		for(unsigned i=0;i<env._paths.size(); i++) {
			ret.arr.push_back(env._paths[i]);
		}
	} else if(argc==3) {
		Variable pathname = argv[2];
		if(cmd.str == "add") {
			for(unsigned i=0;i<pathname.str.size();i++) {
				if(pathname.str[i]=='%') {
					if(pathname.str.substr(i,i+6)== "%ORATR") {
						pathname = pathname.str.substr(0,i) + env._paths[0] + pathname.str.substr(i+6);
					}
				}
			}
			if(isAbsolutePath(pathname.str)) {
				env._paths.push_back(pathname.str);
			} else {
				throw_error(ERROR_FILE);
			}
		} else if(cmd.str == "delete") {
			for(unsigned i=0;i<pathname.str.size();i++) {
				if(pathname.str[i]=='%') {
					if(pathname.str.substr(i,i+6)== "%ORATR") {
						pathname = pathname.str.substr(0,i) + env._paths[0] + pathname.str.substr(i+6);
					}
				}
			}
			for(unsigned i=0;i<env._paths.size(); i++) {
				if(env._paths[i]==pathname.str) {
					env._paths.erase(env._paths.begin() + i);
					break;
				}
			}
		}
	} else {
		throw_error(ERROR_ARGUMENTS);
	}
	return ret;
}

Variable bi_ls(vector<Variable>& argv, Environment& env)
{
	UNUSED env;
	Variable ret;
	vector<pair<string, short> >* Dirlist;
	pair<string, short> files;
	int argc = (int)argv.size();
	if(argc > 4) {
		throw_error(ERROR_ARGUMENTCOUNT);
	}
	if ((argc >=3) && (argv[1].str == "-" ) && (isDir(argv[2].str.c_str()) == 2))  {
		cout << argv[argc-1].str << endl;
		if (argc == 4) {
			//Arguments, and path
			Dirlist = DirectoryListing(argv[3].str.c_str(), argv[2].str.c_str());
		} else if(argc == 3) {
			//Arguments, no path
			Dirlist = DirectoryListing(".", argv[2].str.c_str());
		}
	} else {
		if (argc == 2) {
			//No arguments, just the path
			Dirlist = DirectoryListing(argv[1].str.c_str());
		}else if (argc == 1) {
			//No arguments, no path
			Dirlist = DirectoryListing(".");
		} else {
			Dirlist = NULL;
		}
	}
		
	unsigned int numfiles = Dirlist->size();
	ret.makearr(numfiles);
	for (unsigned int i=0; i<numfiles; i++) {
		files = Dirlist->back();
		Dirlist->pop_back();
		ret.arr[i] = Variable(files.first);
		//ret.arr[i].i = files.second;
	}
	delete Dirlist;
	return ret;
}

Variable bi_mkdir(vector<Variable>& argv, Environment& env)
{
	UNUSED env;
	Variable ret;
	int argc = (int) argv.size();
	if (argc != 2) {
		throw_error(ERROR_ARGUMENTCOUNT);
	}
	MakeDir(argv[1].str.c_str());
	return ret;
}

Variable bi_cd(vector<Variable>& argv, Environment& env)
{
	UNUSED env;
	Variable ret;
	int argc = (int) argv.size();
	if (argc != 2) {
		throw_error(ERROR_ARGUMENTCOUNT);
	}
	ret = chdir(argv[1].str.c_str());
	return ret;
}
Variable bi_cwdir(vector<Variable>& argv, Environment& env)
{
	UNUSED env;
	Variable ret;
	char* buffer;
	int argc = (int) argv.size();
	if (argc != 1) {
		throw_error(ERROR_ARGUMENTCOUNT);
	}
	CurrentWorkingDir(buffer);
	ret = (Variable)buffer;
	return ret;
}
Variable bi_rm(vector<Variable>& argv, Environment& env)
{
	UNUSED env;
	Variable ret;
	string filepath = argv[1].str;
	int argc = (int) argv.size();
	if (argc != 2) {
		throw_error(ERROR_ARGUMENTCOUNT);
	}
	if ( isDir( filepath.c_str() ) ) {
		ret = RecursiveFileIO(filepath.c_str(), opDelete, "");
	} else {
		ret = Remove(argv[1].str.c_str());
	}
	return ret;
}
Variable bi_cp(vector<Variable>& argv, Environment& env)
{
	UNUSED env;
	Variable ret;
	string filepath = argv[1].str;
	int argc = (int) argv.size();
	if (argc != 3) {
		throw_error(ERROR_ARGUMENTCOUNT);
	}
	if ( isDir( filepath.c_str() ) ) {
		ret = RecursiveFileIO(filepath.c_str(), opCopy, argv[2].str.c_str());
	} else {
		ret = Copy(argv[1].str.c_str(), argv[2].str.c_str());
	}
	return ret;
}
Variable bi_mv(vector<Variable>& argv, Environment& env)
{
	UNUSED env;
	Variable ret;
	string filepath = argv[1].str;
	int argc = (int) argv.size();
	if (argc != 3) {
		throw_error(ERROR_ARGUMENTCOUNT);
	}
	if ( isDir( filepath.c_str() ) ) {
		ret = RecursiveFileIO(filepath.c_str(), opMove, argv[2].str.c_str());
	} else {
		ret = Move(argv[1].str.c_str(), argv[2].str.c_str());
	}
	return ret;
}
Variable bi_fecho(vector<Variable>& argv, Environment& env)
{
	Variable ret,filename;
	int argc = (int)argv.size();
	if(argc < 3) {
		throw_error(ERROR_ARGUMENTCOUNT);
	}
	filename = argv[1];
	env.verify(filename);
	if(filename.type != tString) {
		throw_error(ERROR_ARGUMENTS);
	}
	fstream ofile;
	ofile.open(filename.str.c_str(), ios_base::app | ios_base::out | ios_base::binary);
	argv.erase(argv.begin() + 1);
	_bi_printto(argv,env,ofile);
	ofile.close();
	return ret;
}

Variable bi_fread(vector<Variable>& argv, Environment& env)
{
	Variable ret,filename;
	int argc = (int)argv.size();
	if( argc != 2 ) {
		throw_error(ERROR_ARGUMENTCOUNT);
	}
	filename = argv[1];
	env.verify(filename);
	if( filename.type != tString ) {
		throw_error(ERROR_ARGUMENTS);
	}
	
	fstream file;
	string dummy="";
	vector<string> data;
	file.open(filename.str.c_str(), ios_base::in);
	if( !file.is_open() ) {
		throw_error(ERROR_FILE);
	}
	while( (getline(file,dummy)) ) {
		data.push_back(dummy);
	}
	file.close();
	
	env.getvar("__file__").clear();
	env.getvar("__file__").makearr((int)data.size());
	for(unsigned i=0;i<data.size();i++) {
		env.getvar("__file__").arr[i] = data[i];
	}
	
	ret = env.getvar("__file__");
	return ret;
}

Variable bi_system(vector<Variable>& argv, Environment& env)
{
	UNUSED env;
	unsigned argc = argv.size();
	if(argv.size() == 1) {
		throw_error(ERROR_ARGUMENTCOUNT);
	}
	string cmd = "";
	Variable tmp;
	for(unsigned i=1;i<argc;i++) {
		tmp = argv[i];
		env.verify(tmp);
		cmd += tmp.str + " ";
	}
	Variable ret = system(cmd.c_str());
	return ret;
}
